<!doctype html>
<html lang="zh">
<head>
  <meta charset="utf-8">
  <title>KISSY - 全终端适配的 JS 类库</title>
  <meta name="viewport" content="width=device-width">
  <link href="http://fonts.googleapis.com/css?family=Droid+Sans|Lekton|Ubuntu+Mono:400,700" rel="stylesheet">
	<link rel="stylesheet" href="templates/assets/bootstrap.css">
	<link href="templates/assets/normalize.css" rel="stylesheet">
	<link href="templates/assets/kissy.css" rel="stylesheet">
	<link href="templates/assets/prettify.css" rel="stylesheet">
	<link href="templates/assets/forkit.css" rel="stylesheet">
	<script src="templates/assets/jquery.min.js"></script>
	<script src="templates/assets/script.js" type="text/javascript"></script>
	<script src="http://g.tbcdn.cn/trip/kissy/1.4.0/seed-min.js"></script>
	<script src="api/assets/highlight.pack.js"></script>
	<link href="api/assets/tomorrow-night-bright.css" rel=stylesheet />
	<link rel="shortcut icon" href="http://a.tbcdn.cn/s/kissy/favicon.ico">
</head>

<body class="">
    <nav id="sidebar">
    <header>
		<a href="index.html">
			<!--img src="http://gtms04.alicdn.com/tps/i4/T1ceiPFbpcXXcljp_h-200-89.png"-->
			<!--img src="templates/assets/img/logo_6.png"-->
			<!--img src="http://gtms04.alicdn.com/tps/i4/T14oa2FcNcXXaOySEh-180-104.png" alt="" /-->
			<!--img src="http://gtms01.alicdn.com/tps/i1/T1Amq1FaXgXXbXVSUh-180-127.png" alt="" /-->
			<img src="http://gtms02.alicdn.com/tps/i2/T1N0jTXXXjXXay7Rri-175-78.png" alt="" />
		</a>
	</header>
    <ul>
      <li class="nav-divider"><a href="index.html"><img src="templates/assets/img/icon-home.png">首页</a></li>
      <li class="nav-divider"><a href="why-kissy.html"><img src="templates/assets/img/icon-why.png">Why KISSY?</a></li>
      <li><a href="get-started.html"><img src="templates/assets/img/icon-getting-started.png">KISSY 1.4.x 教程大纲</a></li>
      <li class="nav-sub"><a href="module-map.html">核心模块列表</a></li>
      <li class="nav-sub"><a href="kmd.html">KISSY 模块规范 (KMD)</a></li>
      <li class="nav-sub"><a href="gbs.html">浏览器兼容基准(GBS)</a></li>
      <li class="nav-sub"><a href="http://cyj.me/jquery-kissy-rosetta/">jQuery KISSY 对比手册</a></li>
      <li class="nav-sub"><a href="http://gallery.kissyui.com/guide">KISSY 组件开发规范</a></li>
      <li class="nav-sub nav-divider"><a href="history.html">历史版本</a></li>
      <li><a href="">API Doc</a></li>
      <li><a href="http://demo.kissyui.com">Demos</a></li>
      <li class="nav-divider"><a href="http://gallery.kissyui.com">KISSY Gallery</a></li>
      <li><a href="tools.html">KISSY 项目构建工具</a></li>
      <li class="nav-sub"><a href="kmc.html">KS Module Compiler</a></li>
      <li class="nav-sub"><a href="http://abc.f2e.taobao.net">ABC</a></li>
      <li class="nav-sub nav-divider"><a href="clam.html">Clam</a></li>
      <li><a href="third-party-lib.html">第三方代码库</a></li>
      <li class="nav-sub"><a href="https://github.com/lorrylockie/tpap/wiki">面向第三方安全的 KISSY</a></li>
      <li class="nav-sub"><a href="http://www.builive.com/demo/index.php">BUI</a></li>
      <li class="nav-sub nav-divider"><a href="http://work.tmall.net/muidoc/build/">MUI</a></li>
      <li><a href="https://github.com/kissyteam/kissy/blob/master/CONTRIBUTING.md">为 KISSY Core 贡献代码</a></li>
      <li class="nav-sub"><a href="http://google-styleguide.googlecode.com/svn/trunk/htmlcssguide.xml">HTML/CSS编码规范</a></li>
      <li class="nav-sub nav-divider"><a href="http://docs.kissyui.com/source/tutorials/style-guide/google/javascriptguide.xml">JavaScript 编码规范</a></li>
	  <li><a href="upgrade.html"><img src="templates/assets/img/icon-documentation.png">1.3.x->1.4.0 升级指南</a></li>
	  <li><a href="faq.html"><img src="templates/assets/img/icon-faqs.png">FAQ</a></li>
      <li><a href="https://github.com/kissyteam/kissy"><img src="templates/assets/img/icon-github.png">GitHub</a></li>
	  <li><a href="core-team.html"><img src="templates/assets/img/icon-google-plus.png">KISSY 核心小组</a></li>
    </ul>
  </nav>

  <div id="content">
    <article>
      

	<h1>KISSY 模块定义规范（KMD）</h1>
<hr>
<p>模块：即一段独立成文件的代码单元。最常见的浏览器端 JavaScript 单元是：</p>
<pre><code>// within a file
(function(doc){
    // 模块代码
})(document);</code></pre>
<p>这段代码用闭包来约束执行上下文，避免对全局命名空间的污染。随着代码复杂度增加，模块格式开始融入团队协作和性能要求，模块格式也从单纯的<code>匿名闭包函数</code>演变为<code>模块定义规范</code>。</p>
<p>首先要明确，模块化的目标是：</p>
<ol>
<li>代码单元冠以命名，增强代码段的辨识度</li>
<li>建立代码之间的依赖关系，降低代码段之间的耦合</li>
<li>命名空间和上下文管理，减少代码段之间的相互冲突</li>
<li>形成模块规范，提高代码段的复用性</li>
</ol>
<p>因此，一个完整的模块应当包含这几个属性</p>
<ol>
<li>模块名</li>
<li>实现逻辑</li>
<li>返回值</li>
<li>所依赖的模块</li>
</ol>
<p>KISSY 在诞生之初就确立了模块化的架构，以此抽象出现在的 KISSY 模块定义规范（KISSY Module Defination，简称 KMD）。这份规范明确了 KISSY 所遵循的书写格式和基本交互。</p>
<h1>API 规范</h1>
<h2>add() <code>Function</code></h2>
<p><code>add</code>函数挂载在全局对象<code>KISSY</code>上，用来定义模块。</p>
<pre><code>add(name?,factory?,deps)</code></pre>
<p>其中字符串<code>name</code>表示模块的注册名称，<code>factory</code>表示模块的主内容/逻辑，<code>deps</code>是一个对象，表示模块依赖</p>
<h3>add(name,factory)</h3>
<p><code>add</code>函数第一个参数是<code>name</code>，表示要注册模块的名字，<code>factory</code>可以是函数，也可以是对象或字符串。</p>
<p><code>factory</code>为函数时，表示模块的实现逻辑，回调函数回传第一个参数总是<code>KISSY</code>全局对象，约定写为<code>S</code>，该函数的返回值即为模块的返回值，该返回值将会传入调用这个模块的沙箱中：</p>
<pre><code>add(&#39;module-name&#39;,function(S){
    // 模块代码
    return {
        &#39;foo&#39;:&#39;bar&#39;
    };
});</code></pre>
<p><code>factory</code>为对象或者字符串是，只表示该模块的内容就是此对象或字符串：</p>
<pre><code>add(&#39;module-name&#39;,&#39;I am a template, My Name is {{module-name}}&#39;);
add(&#39;module-name&#39;,{
    &#39;foo&#39;:&#39;bar&#39;    
});</code></pre>
<h3>add(name,factory,deps)</h3>
<p>当给<code>add</code>函数传入最后一个参数<code>deps</code>，这时<code>deps</code>表示该模块的依赖，其中<code>requries</code>属性是一个数组，数组元素可以是其他模块的名字<code>name</code>，也可以是指向模块的路径，<code>factory</code>如果是函数，则函数中的回传参数除第一个<code>S</code>（全局对象 KISSY）外依次对应每个模块的返回值：</p>
<pre><code>add(&#39;module-name&#39;,function(S,A,B,C){
    // 模块代码    
    return sth;
},{
    requires:[
        &#39;mod-a&#39;,&#39;mod-b&#39;,&#39;mod-c&#39;
    ]
});</code></pre>
<h3>add(factory,deps)</h3>
<p><code>name</code>参数可以省略，但仅限于一个 JS 文件包含一个<code>add()</code>（这时文件名可以用作模块名），如果一个文件包含多个<code>add()</code>，则必须为每个<code>add()</code>指定模块名，即<code>name</code>参数不可省略，比如：</p>
<pre><code>// a.js，这里的add()没有指定name
add(function(S){
    // A 模块逻辑
});

// b.js
add(function(S,A){
    // B 模块逻辑
},{
    requires:[&#39;path/to/a.js&#39;]    
});</code></pre>
<p>而这种用法是错误的：</p>
<pre><code>// a.js，一个 JS 文件中包含了两段add()，且都没有指定模块名
add(function(S){
    // 逻辑段1
});
add(function(S){
    // 逻辑段2
});</code></pre>
<p>一个文件带有多个<code>add()</code>时，必须补全每个<code>add()</code>的<code>name</code>，比如正确的写法是：</p>
<pre><code>// a.js 一个 JS 文件包含多段add()，必须补全每个模块名称
add(&#39;mod-a&#39;,function(S){
    // 逻辑段A
});
add(&#39;mod-b&#39;,function(S){
    // 逻辑段B
});</code></pre>
<h2>require() <code>Function</code></h2>
<h3>require(name)</h3>
<p>获取已经注册的模块的返回值，这里注意，要保证所有依赖的模块都已经注册过，<code>require()</code>函数才会正确返回，如果有未注册的模块，<code>require()</code>不会计算依赖并动态加载。该函数只是针对已经注册过模块起作用，是一种快捷调用模块返回值的方法：</p>
<pre><code>// 注册模块
add(&#39;a&#39;,{
    &#39;foo&#39;:&#39;bar&#39;    
});

// 获取已经注册模块的值
require(&#39;a&#39;); // =&gt; {&#39;foo&#39;:&#39;bar&#39;}</code></pre>
<h2>use() <code>Function</code></h2>
<p>异步调用模块，并在模块加载完成后运行沙箱逻辑。</p>
<h3>use(name,sandbox)</h3>
<p><code>name</code>是一个字符串，表示要载入模块的名字（列表），如果有多个名字，则中间用逗号分隔，函数<code>sandbox</code>为加载并注册完成这些模块后的回调逻辑，带入第一个参数为<code>KISSY</code>全局对象，默认缩写为<code>S</code>，其他参数依次带入所载入的模块返回的对象。</p>
<pre><code>use(&#39;mod-a, mod-b&#39;,function(S,ModA,ModB){
    // 沙箱逻辑
});</code></pre>
<p>其中，<code>name</code>字段中的每个单元，可以用模块名称表示，也可以用模块文件对应的路径表示，这时，模块定义时的名称也应当和这里的路径保持一致，比如：</p>
<pre><code>use(&#39;path/to/mod-a, path/to/mod-b&#39;,function(S,ModA,ModB){
    // 沙箱逻辑    
});</code></pre>
<p>例子中的模块 A 和模块 B 在注册模块名时的书写方法请参照<code>add()</code>。</p>
<h2>config() <code>Function</code></h2>
<p>全局配置函数，用以读写全局配置项，包括注册<strong>包</strong>、预注册<strong>模块</strong>名称，模块文件的引用规则等等。</p>
<h3>config(name,pkg)</h3>
<p>写配置项，<code>name</code>表示配置项名称，<code>pkg</code>表示配置项的值，其中配置项包括：</p>
<ul>
<li>modules，JSON 对象，预注册的模块关系依赖</li>
<li>combine，Boolean值，是否开启动态合并</li>
<li>comboMaxFileNum，数字类型，最动态合并文件最大个数</li>
<li>packages，JSON 对象，包配置</li>
<li>tag，字符串，异步加载文件时所带的时间戳</li>
<li>debug，Boolean值，是否开启debug模式，不开启，将默认加载<code>&#39;-min&#39;</code>文件</li>
<li>charset，字符串，指示所有模块文件编码格式，默认为<code>utf-8</code></li>
<li>base，字符串，类库所在的URL</li>
</ul>
<p><strong>注册包</strong>：包是一个名字，用来映射某个URL地址，方便记忆和引用，比如：</p>
<pre><code>// 配置包
config(&#39;packages&#39;,{
    &#39;pkg-name&#39;:{
        base:&#39;http://path/to/project/&#39;
    }
});

// 使用包下辖的模块，载入了 http://path/to/project/pkg-name/a.js
use(&#39;pkg-name/a&#39;,function(S,A){
    // 沙箱逻辑    
});</code></pre>
<p>使用<code>ignorePackageNameInUri</code>属性来说明是否在请求模块路径中省去<code>pkg-name</code>，比如下面代码也是正确的：</p>
<pre><code>// 配置包
config(&#39;packages&#39;,{
    &#39;pkg-name&#39;:{
        base:&#39;http://path/to/project/pkg-name/&#39;,
        ignorePackageNameInUri:true
    }
});

// 使用包下辖的模块，载入了 http://path/to/project/pkg-name/a.js
use(&#39;pkg-name/a&#39;,function(S,A){
    // 沙箱逻辑    
});</code></pre>
<p>当开启了<code>combine:true</code>，可使用<code>group</code>属性来配置多个包之间的合并请求：</p>
<pre><code>// 配置包，并给定分组名 group
config(&#39;packages&#39;,{
    &#39;pkg-a&#39;:{
        base:&#39;http://path/to/project/pkg-a/&#39;,
        group:&#39;my&#39;
    },
    &#39;pkg-b&#39;:{
        base:&#39;http://path/to/project/pkg-b/&#39;,
        group:&#39;my&#39;
    },
});

// 使用包下辖的模块
use(&#39;pkg-a/mod1,pkg-b/mod2&#39;,function(S){
    // 沙箱逻辑    
});</code></pre>
<p>开启<code>combine:true</code>后，这条<code>use()</code>语句将只会发起一个 HTTP 请求，而非两个。</p>
<p><code>pkg-name</code>也可以用于<code>add()</code>函数，比如：</p>
<pre><code>// 注册模块文件 
// http://path/to/project/pkg-name/a.js
add(&#39;pkg-name/a&#39;,function(S){
    // 模块 A 的逻辑    
});</code></pre>
<p><strong>预注册模块</strong>：由于浏览器端加载脚本都是异步，因此如果模块之间有依赖，主逻辑只能在加载 A 模块后才知道并加载 A 的依赖。因此加载过程为串行。为了降低串行的性能损耗，<code>config()</code>可以预先注册模块的依赖关系，一次性加载模块和与之关联的依赖，比如</p>
<pre><code>// 预注册模块依赖
config(&#39;modules&#39;,{
    &#39;mod-a&#39;:{
        requires:[&#39;mod-b&#39;,&#39;mod-c&#39;]
    },
    &#39;mod-b&#39;:{
        requries:[&#39;mod-d&#39;,&#39;mod-e&#39;]
    }
});

// use() 模块时，在配置了 combine:true 后，将会合并载入模块及其依赖
use(&#39;mod-a, mod-b&#39;, function(S,ModA,ModB){
    // 沙箱逻辑    
});</code></pre>
<p><strong>模块别名</strong>：在定义模块时，可以通过<code>alias</code>来定义模块别名</p>
<pre><code>// 定义模块的别名
config(&#39;modules&#39;,{
    &#39;mod-a&#39;:{
        alias:[&#39;mod-b/1.2&#39;] // 数组长度为1
    }
});

// 正常使用模块
use(&#39;mod-a&#39;,function(S){});</code></pre>
<h3>config(cfg)</h3>
<p>写配置项的另外一种写法，即传入一个JSON对象<code>cfg</code>：</p>
<pre><code>config({
    modules:{
        // 模块依赖关系Map
    },
    packages:{
        // 包配置
    },
    combine:true,
    charset:&#39;utf-8&#39;,
    debug:false
    //...
});</code></pre>
<h3>config(name)</h3>
<p>读配置项</p>
<pre><code>// 获取当前的全局配置
var combine = config(&#39;combine&#39;);</code></pre>
<h2>小结</h2>
<p>以上为 KMD 模块定义规范的全部内容，经常使用的 API 只有 <code>use</code>、<code>add</code>、<code>config</code>。</p>
<p>KMD 规范诞生之初还未有<a href="http://wiki.commonjs.org/wiki/CommonJS">CommonJS规范</a>以及<a href="https://github.com/amdjs/amdjs-api/wiki/AMD">AMD</a> 和 <a href="https://github.com/seajs/seajs/issues/242">CMD</a>。经典的 <a href="http://yuilibrary.com/yui/docs/yui/loader.html">YUI3 Loader</a> 受限于单一的业务场景（门户网站），至今未完全形成规范。KMD 作为一个完整的模块规范，崇尚约定，保持简单，并在 Loader 的实现过程中，新增了别名、包配置、动态combo等实际工作中常用的功能，即有别于 AMD 和 CMD 的过于纯粹，又不同于 YUILoader 的繁杂配置，保持其易用和实用。</p>


<div id="disqus_thread"></div>
<script>
    if((window.location.hostname.indexOf("kissyui.com")!=-1 )&& window.localStorage.getItem("kissy-commment")!="0"){
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
    var disqus_shortname = 'kissy-docs'; // required: replace example with your forum shortname

    // The following are highly recommended additional parameters. Remove the slashes in front to use.
     //var disqus_identifier = '/anim';
     //var disqus_url = window.location;

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
    }
</script>



      
  <style>
	.github-btn {
		border: 0 none;
		overflow: hidden;
		margin-top:4px;
	}
	footer {
		border-top:1px solid #e2e2e2;
		padding-top:20px;
		clear:both;
	}
	/* iPhone 及以下 */
	@media only screen and (max-width: 767px) {
		.github-link {
			display:none;
		}
	}
  </style>
  <footer>




	<div class="text-center">
		©2013 - 2033 KISSY UI LIBRARY
		<br /> <iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=kissyteam&amp;repo=kissy&amp;type=watch&amp;count=true" width="100" height="20" title="Star on GitHub"></iframe> 
	<iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=kissyteam&amp;repo=kissy&amp;type=fork&amp;count=true" width="102" height="20" title="Fork on GitHub"></iframe>
	</div>
  </footer>
    </article>
  </div>
  <a target="_blank" href="https://github.com/kissyteam/kissy" class="github-link"><img alt="Fork me on GitHub" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" style="position: absolute; top: 0; right: 0; border: 0; z-index: 50"></a>
  <script>
	var S = KISSY;
	(function(){
		S.use('node',function(S){
			S.all('code').each(function(node){
				var className = node.attr('class');
				if(/^lang-/.test(className)){
					var tc = className.replace(/^lang-/,'');
					node.replaceClass(className,tc);
				}
			});
			hljs.tabReplace = '    ';
			hljs.initHighlighting();
		});
	})();
	(function(){
		var h3s = document.getElementsByTagName('h3');
		for(var i = 0;i<h3s.length;i++){
			var str = S.trim(h3s[i].innerHTML);
			try{
				str = str.match(/\w+/)[0];
			}catch(e){
				continue;
			}
			h3s[i].innerHTML = '<a name="'+str+'"></a>' + h3s[i].innerHTML;
		}
	})();
  </script>
</body>
</html>
